/**
 * @file module.h
 * @brief describes a module which is a collection of gates
 * @author Scott Moyers
 * @date 2008
 */

#ifndef MY_MODULE_H
#define MY_MODULE_H

#include "gate.h"
#include "truth_table.h"
#include "dSFMT.h"

/**
 * @brief a structure for a module
 */
struct Module {
	int id;                  /**< unique id for the module            */
	unsigned int num_inputs; /**< number of inputs to the module      */
	unsigned int num_gates;  /**< total number of gates in the design */
	struct Gate *circuit;    /**< topologically sorted array of gates */
	unsigned int **signals;  /**< all signals [num_inputs + num_gates][signal_width] */
	double fitness;          /**< how well the module implements a given truth table */
};

/**
 * Gets the next available id for a module.
 * @return next available module id
 */
unsigned long next_module_id();

/**
 * gets the total number of signals in a module
 * @param m the module
 */ 
#define num_signals(m) ((m)->num_inputs + (m)->num_gates)

/**
 * returns the width of a signal in ints given the
 * number of inputs to the module / truthtable
 * @param i number of inputs to the module / truthtable
 */
#define signal_width(i) ((unsigned)1 << (i >= 5 ? i - 5 : 0))

/**
 * set 1 bit of a signal
 * @param s the signal
 * @param x the bit to set
 */
#define set_signal_bit(s, x)   ((s)[(x) / 32] |=  (1 << ((x) % 32)))

/**
 * clear 1 bit of a signal
 * @param s the signal
 * @param x the bit to clear
 */
#define clear_signal_bit(s, x) ((s)[(x) / 32] &= ~(1 << ((x) % 32)))

/**
 * get 1 bit of a signal
 * @param s the signal
 * @param x the bit to get
 * @return the value of bit x in the signal
 */
#define get_signal_bit(s, x) ((s)[(x) / 32] >> (((x) % 32) & 0x1))

/**
 * mask any unused bits if the number of inputs is < 5 (< 32 combinations)
 * @param s the signal
 * @param n the number of inputs the signal represents
 */
#define mask_signal(s, n)						\
	do {								\
		if (n < 5)						\
			s[0] &= (1 << (1 << n)) - 1;			\
	}while(0)							\
		
/**
 * function for creating a new module
 * @param id a unique id for the module
 * @param num_inputs number of inputs
 * @param num_gates number of gates
 * @return a pointer to the new module
 */
struct Module *new_module(int id, int num_inputs, int num_gates);

/**
 * function for deleting a module
 * @param m the module to delete
 */
void free_module(struct Module *m);

/**
 * simulates the entire module to validate all the signals
 */
void execute_module(struct Module *m);

/**
 * colour all the gates in the module the given colour
 * @param m the module to colour
 * @param c the colour
 */
void colour_module(struct Module *m, enum Colour c);

/**
 * colour all the gates attached to the inputs of
 * @param m the module
 * @param n the number of the gates in the module
 * @param c the colour
 */
void colour_tree(struct Module *m, int n, enum Colour c);

/**
 * print a signal from a module to the given file
 * @param fp file pointer
 * @param s the signal
 * @param n the width of the signal
 */
void fprint_signal(FILE *fp, unsigned int *s, int n);

/**
 * print a module as a list of gates
 * mainly useful for debugging
 * @param fp file pointer
 * @param m module that contains the signal
 */
void fprint_module(FILE *fp, struct Module *m);

/**
 * function to allocate the 2D signal array
 * @param rows number of rows
 * @param cols number of columns
 * @return newly allocated 2D array of size number of signals * signal width
 */
unsigned int **malloc_signals(unsigned int rows, unsigned int cols);


/**
 * function to free the signals array
 * @param sig the signal array to free
 * @param rows number of rows
 */
void free_signals(unsigned int **sig, unsigned int rows);

/**
 * compares two signals
 * @param a first signal
 * @param b seconds signal
 * @param w width of the signals (they should both be the same width)
 * @retval -1 if a is less than b
 * @retval  1 if a is greater than b
 * @retval  0 if a is equal to b
 */
int cmp_signals(unsigned int a[], unsigned int b[], unsigned int w);

/**
 * counts the number of bits that differ between two signals
 * @param a first signal
 * @param b seconds signal
 * @param w width of the signals (they should both be the same width)
 * @return number of bits that differ between the two signals
 */
int diff_pop_cnt(unsigned int a[], unsigned int b[], unsigned int w);

/**
 * make a new copy of a module
 * @param m the module to copy
 * @return a new copy of the input module
 */
struct Module *copy_module(struct Module const *m);

/**
 * get the depth of the module
 * this is the longest path from the inputs to the outputs
 * @param m the module to find the depth for
 */
unsigned int depth_module(struct Module *m);

/**
 * sum up all the differences between the best signal matches
 * this tells us how close our module is to implementing the
 * given truth table
 * @param m the module
 * @param t the truth table
 * @return sum of differences between the best signal matches
 */
int min_signal_diff(struct Module *m, struct TruthTable *t);

/**
 * comparison function used to sort module lists by fitness
 * @param value1 first value
 * @param value2 second value
 * @return   A negative value if value1 should be sorted before value2, 
 *           a positive value if value1 should be sorted after value2, 
 *           zero if value1 and value2 are equal.
 */
int compare_module_fitness(void *value1, void *value2);

/**
 * checks if the modules circuit is cyclic
 * @param m the module
 * @retval 1 if the module is cyclic
 * @retval 0 if the module is not cyclic
 */
unsigned int is_cyclic(struct Module *m);

/**
 * lays out the gates in a module so their
 * coordinates are suitable for displaying
 * in the GUI
 * @param m the module to layout
 */
void layout_module(struct Module *m);

#endif
